#include "UniversalSerialPort.hpp"
#include "stdio.h"
/*  库文件  */
#include "system.hpp"
#include "apm32f0xx_rcm.h"
#include "apm32f0xx_gpio.h"
#include "apm32f0xx_usart.h"
#include "apm32f0xx_misc.h"


#define SERIALPORT_NUMBER   6   //  串口数
#define MAX_DATA_LENGTH 64 //数据接收最大长度

static const struct {
    USART_T * usart1;
    PeripheralClock_t usart1_port_clk;
    PeripheralClock_t usart1_peripheral_clk;
    GPIO_T * usart1_port;
    GPIO_PIN_T usart1_tx_pin;
    GPIO_PIN_T usart1_rx_pin;
    GPIO_PIN_SOURCE_T usart1_tx_pin_source;
    GPIO_PIN_SOURCE_T usart1_rx_pin_source;
    GPIO_AF_T usart1_af_pin;
    IRQn_Type usart1_irq;

    USART_T * usart6;
    PeripheralClock_t usart6_port_clk;
    PeripheralClock_t usart6_peripheral_clk;
    GPIO_T * usart6_port;
    GPIO_PIN_T usart6_tx_pin;
    GPIO_PIN_T usart6_rx_pin;
    GPIO_PIN_SOURCE_T usart6_tx_pin_source;
    GPIO_PIN_SOURCE_T usart6_rx_pin_source;
    GPIO_AF_T usart6_af_pin;
    IRQn_Type usart6_irq;
}__hardware_description = {
    .usart1 = USART1,
    .usart1_port_clk = CLK_GPIOA,
    .usart1_peripheral_clk = CLK_USART1,
    .usart1_port = GPIOA,
    .usart1_tx_pin = GPIO_PIN_9,
    .usart1_rx_pin = GPIO_PIN_10,
    .usart1_tx_pin_source = GPIO_PIN_SOURCE_9,
    .usart1_rx_pin_source = GPIO_PIN_SOURCE_10,
    .usart1_af_pin = GPIO_AF_PIN1,
    .usart1_irq = USART1_IRQn,

    .usart6 = USART6,
    .usart6_port_clk = CLK_GPIOA,
    .usart6_peripheral_clk = CLK_USART6,
    .usart6_port = GPIOA,
    .usart6_tx_pin = GPIO_PIN_4,
    .usart6_rx_pin = GPIO_PIN_5,
    .usart6_tx_pin_source = GPIO_PIN_SOURCE_4,
    .usart6_rx_pin_source = GPIO_PIN_SOURCE_5,
    .usart6_af_pin = GPIO_AF_PIN5,
    .usart6_irq = USART3_6_IRQn,

};

class _UniversalSerialPort : public UniversalSerialPort{
public:
    _UniversalSerialPort(unsigned char serial_port_number);
    virtual bool init();
    virtual int send(void *data,int length);
    virtual int receive(void *data);

    void interruptHandler();

private:
    QueueHandle_t usart_queue = NULL;
    SemaphoreHandle_t usart_semaphore = NULL;
};

/* 获取串口实例 */
static _UniversalSerialPort * _uninversal_serial_port[SERIALPORT_NUMBER] = {nullptr};


UniversalSerialPort::UniversalSerialPort(unsigned char serial_port_number)
    : port_number(serial_port_number){}

UniversalSerialPort * UniversalSerialPort::getInstance(unsigned char serial_port_number){
    if( _uninversal_serial_port[serial_port_number] == nullptr ){
        _uninversal_serial_port[serial_port_number] = new _UniversalSerialPort(serial_port_number);
        _uninversal_serial_port[serial_port_number]->init();
    }
    return _uninversal_serial_port[serial_port_number];
}

_UniversalSerialPort::_UniversalSerialPort(unsigned char serial_port_number)
    : UniversalSerialPort(serial_port_number){}

bool _UniversalSerialPort::init(){
    
    GPIO_Config_T gpio_configuration;
    USART_Config_T usart_configuration;
    switch(port_number){
        case 0 :
            System_setPeripheralClockEnable(__hardware_description.usart1_port_clk,TRUE);
            System_setPeripheralClockEnable(__hardware_description.usart1_peripheral_clk,TRUE);
            
            GPIO_ConfigPinAF(__hardware_description.usart1_port, __hardware_description.usart1_tx_pin_source, __hardware_description.usart1_af_pin);
            GPIO_ConfigPinAF(__hardware_description.usart1_port, __hardware_description.usart1_rx_pin_source, __hardware_description.usart1_af_pin);

            gpio_configuration.pin = __hardware_description.usart1_tx_pin;
            gpio_configuration.mode = GPIO_MODE_AF;
            gpio_configuration.outtype = GPIO_OUT_TYPE_PP;
            gpio_configuration.speed = GPIO_SPEED_50MHz;
            gpio_configuration.pupd = GPIO_PUPD_PU;
            GPIO_Config(__hardware_description.usart1_port,&gpio_configuration);
            gpio_configuration.pin = __hardware_description.usart1_rx_pin;
            GPIO_Config(__hardware_description.usart1_port,&gpio_configuration);

            usart_configuration.baudRate = 9600;
            usart_configuration.wordLength = USART_WORD_LEN_8B;
            usart_configuration.parity = USART_PARITY_NONE;
            usart_configuration.stopBits = USART_STOP_BIT_1;
            usart_configuration.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
            usart_configuration.mode = USART_MODE_TX_RX;
            USART_Config(__hardware_description.usart1,&usart_configuration);

            USART_EnableInterrupt(__hardware_description.usart1, USART_INT_RXBNEIE);
            NVIC_EnableIRQRequest(__hardware_description.usart1_irq,3);

            USART_Enable(__hardware_description.usart1);   
            usart_queue = xQueueCreate(MAX_DATA_LENGTH , sizeof(unsigned char));
            if( usart_queue == NULL )printf("usart1_queue create error\r\n");

            usart_semaphore = xSemaphoreCreateCounting(MAX_DATA_LENGTH , 0 );
            if( usart_semaphore == NULL )printf("usart1_queue create error\r\n");

            break;
        case 1 :
            break;
        case 5 :
            System_setPeripheralClockEnable(__hardware_description.usart6_port_clk,TRUE);
            System_setPeripheralClockEnable(__hardware_description.usart6_peripheral_clk,TRUE);
            
            GPIO_ConfigPinAF(__hardware_description.usart6_port, __hardware_description.usart6_tx_pin_source, __hardware_description.usart6_af_pin);
            GPIO_ConfigPinAF(__hardware_description.usart6_port, __hardware_description.usart6_rx_pin_source, __hardware_description.usart6_af_pin);

            gpio_configuration.pin = __hardware_description.usart6_tx_pin;
            gpio_configuration.mode = GPIO_MODE_AF;
            gpio_configuration.outtype = GPIO_OUT_TYPE_PP;
            gpio_configuration.speed = GPIO_SPEED_50MHz;
            gpio_configuration.pupd = GPIO_PUPD_PU;
            GPIO_Config(__hardware_description.usart6_port,&gpio_configuration);
            gpio_configuration.pin = __hardware_description.usart6_rx_pin;
            GPIO_Config(__hardware_description.usart6_port,&gpio_configuration);

            usart_configuration.baudRate = 9600;
            usart_configuration.wordLength = USART_WORD_LEN_8B;
            usart_configuration.parity = USART_PARITY_NONE;
            usart_configuration.stopBits = USART_STOP_BIT_1;
            usart_configuration.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
            usart_configuration.mode = USART_MODE_TX_RX;
            USART_Config(__hardware_description.usart6,&usart_configuration);

            USART_EnableInterrupt(__hardware_description.usart6, USART_INT_RXBNEIE);
            NVIC_EnableIRQRequest(__hardware_description.usart6_irq,2);

            USART_Enable(__hardware_description.usart6);   

            usart_queue = xQueueCreate(MAX_DATA_LENGTH , sizeof(unsigned char));
            if( usart_queue == NULL ){
                printf("usart6_queue create error\r\n");
            }

            usart_semaphore = xSemaphoreCreateCounting(MAX_DATA_LENGTH , 0 );
            break;
        default:
             return false;
            }
            
    return true;
}

int _UniversalSerialPort::send(void *data,int length){
    unsigned char * send_data = reinterpret_cast<unsigned char *>(data);
    const unsigned int time_out = 2000;
    unsigned int time_count = 0;
    switch(port_number){
        case 0 :
            for ( int n = 0; n < length; n++ ){
                while ( USART_ReadStatusFlag(__hardware_description.usart1,USART_FLAG_TXBE) == RESET ){
                    time_count ++ ;
                    if( time_count > time_out ) return -1;
                }
                time_count = 0;
                USART_TxData(__hardware_description.usart1,send_data[n]);
                while ( USART_ReadStatusFlag(__hardware_description.usart1,USART_FLAG_TXC) == RESET ){
                    time_count ++ ;
                    if( time_count > time_out ) return -1; 
                }
                time_count = 0;
            }
            break;
        case 1 :
            break;
        case 5 :
            for ( int n = 0; n < length; n++ ){
                while ( USART_ReadStatusFlag(__hardware_description.usart6,USART_FLAG_TXBE) == RESET ){
                    time_count ++ ;
                    if( time_count > time_out ) return -1;
                }
                time_count = 0;
                USART_TxData(__hardware_description.usart6,send_data[n]);
                while ( USART_ReadStatusFlag(__hardware_description.usart6,USART_FLAG_TXC) == RESET ){
                    time_count ++ ;
                    if( time_count > time_out ) return -1; 
                }
                
                time_count = 0;
            }
            break;
        default:
            return 0;
    }
    return length;
}

const int WAIT_TIME = 10;   // 等待时间 单位是时钟周期
int _UniversalSerialPort::receive(void *data){
    int index = 0;
    unsigned char *rxbuffer = (unsigned char *)data;
    while( xSemaphoreTake(usart_semaphore , WAIT_TIME) == pdTRUE ){
        if (xQueueReceive(usart_queue, &rxbuffer[index], WAIT_TIME) == pdTRUE){
            index ++ ;
        }
    }
    return index;
}

void _UniversalSerialPort::interruptHandler() {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    BaseType_t result;
    switch( port_number ){
        case 0:
            if (USART_ReadStatusFlag(__hardware_description.usart1, USART_FLAG_RXBNE) == SET){
                unsigned char data = USART_RxData(__hardware_description.usart1);
                xQueueSendFromISR(usart_queue, &data, &xHigherPriorityTaskWoken);
                xSemaphoreGiveFromISR(usart_semaphore , &xHigherPriorityTaskWoken);
            }
            break;
        case 5:
            if (USART_ReadStatusFlag(__hardware_description.usart6, USART_FLAG_RXBNE) == SET){
                unsigned char data = USART_RxData(__hardware_description.usart6);
                xQueueSendFromISR(usart_queue, &data, &xHigherPriorityTaskWoken);
                xSemaphoreGiveFromISR(usart_semaphore , &xHigherPriorityTaskWoken);
            }
            break;
        default:
            break;
    }
}


extern "C" __attribute__((interrupt()))
void USART2_IRQHandler(void){

}

extern "C" __attribute__((interrupt()))
void USART1_IRQHandler(void){
    if ( USART_ReadIntFlag(USART1,USART_INT_FLAG_RXBNE) != RESET ){
        if ( _uninversal_serial_port[0] != nullptr ){
            _uninversal_serial_port[0]->interruptHandler();
        }
        USART_ClearIntFlag(USART1,USART_INT_FLAG_RXBNE);
    }
}

extern "C" __attribute__((interrupt()))
void USART3_6_IRQHandler(void){
    /* Spindle Usart6 接收 */
    if ( USART_ReadIntFlag(USART6,USART_INT_FLAG_RXBNE) != RESET ){
        if ( _uninversal_serial_port[5] != nullptr ){
            _uninversal_serial_port[5]->interruptHandler();
        }
        USART_ClearIntFlag(USART6,USART_INT_FLAG_RXBNE);
    }

}